package mcom.xmks.bluetooth.mesh;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Intent;
import android.os.Build;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import com.google.android.material.progressindicator.LinearProgressIndicator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.wch.meshlib.util.BLEPermissionUtil;
import mcom.xmks.bluetooth.mesh.base.ScanBaseActivity;
import mcom.xmks.bluetooth.mesh.constant.IntentConstant;
import mcom.xmks.bluetooth.mesh.core.BleDevice;
import mcom.xmks.bluetooth.mesh.dialog.DeviceListAdapter;
import mcom.xmks.bluetooth.mesh.utils.ConvertUtil;
import mcom.xmks.bluetooth.mesh.utils.LogTool;

public class ScanActivity extends ScanBaseActivity {
    /**蓝牙别名*/
    private static final String KEY_ALIAS="alias";
    /**蓝牙别名*/
    private static final String KEY_IDENTIFIER="identifier";
    private MenuItem startScan,stopScan;
    /**连接状态*/
    private boolean isScanning=false;
    /**源活动类名称*/
    private String sourceActivityClass=null;
    /**目标活动类名称*/
    private String targetActivityClass=null;
    /**仅扫描配置的BLE设备*/
    private boolean onlyScanConfiguredBLE=false;
    /**过滤设备·*/
    private List<String> filterDevices=null;
    private DeviceListAdapter adapter=null;
    private Intent intent=null;

    private LinearProgressIndicator pbIndicator;
    private RecyclerView rvDevice;
   private ActivityResultLauncher<Intent> activityResult  = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
                if(result.getResultCode()==RESULT_OK){
                    Intent intent = new Intent();
                    intent.putExtra(IntentConstant.REFRESH_LIST,true);
                    setResult(RESULT_OK,intent);    //返回到主页面
                    finish();
                }
            });
    @Override
    protected void setView() {
        setContentView(R.layout.activity_scan);
        ActionBar actionBar = getSupportActionBar();
        if(actionBar!=null){
            actionBar.setTitle("搜索附近设备");
            actionBar.setHomeButtonEnabled(true);  //启用返回按钮
            actionBar.setDisplayHomeAsUpEnabled(true); //显示返回按钮
        }
        rvDevice=this.findViewById(R.id.rvDevice);
        pbIndicator=this.findViewById(R.id.pbIndicator);
    }
    @Override
    protected void initWidget() {
        intent=getIntent();
        if(intent.hasExtra(IntentConstant.SCAN_FILTER_DEVICE)) {
            filterDevices=intent.getStringArrayListExtra(IntentConstant.SCAN_FILTER_DEVICE);
        }
        if(intent.hasExtra(IntentConstant.SCAN_SOURCE_ACTIVITY)) {
            sourceActivityClass = intent.getStringExtra(IntentConstant.SCAN_SOURCE_ACTIVITY);
        }
        if(intent.hasExtra(IntentConstant.SCAN_TARGET_ACTIVITY)) {
            targetActivityClass = intent.getStringExtra(IntentConstant.SCAN_TARGET_ACTIVITY);
        }
        onlyScanConfiguredBLE=intent.getBooleanExtra(IntentConstant.SCAN_ONLY_CONFIGURED,false);
        adapter=new DeviceListAdapter(device -> {
            setResult(device.getAddress());
        });
        this.rvDevice.setAdapter(adapter);
        this.rvDevice.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        this.rvDevice.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        startScan();
    }
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                break;
            case R.id.startScan:
                startScan();
                break;
            case R.id.stopScan:
                stopScan();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_scan,menu);
        menu.findItem(R.id.startScan).setVisible(!isScanning);
        menu.findItem(R.id.stopScan).setVisible(isScanning);
        return true;
    }
    @Override
    public void onBackPressed() {
        stopScan();
        super.onBackPressed();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        LogTool.d("ScanActivity destroy");
    }

    private void startScan(){
        //权限检查
        if(!checkPermissionsAllowed()){
            requestPermissions();
            return;
        }
        //检查蓝牙状态
        if(!isBluetoothOpened()){
            openBluetooth();
            return;
        }
        //检查定位是否开启
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            if(!BLEPermissionUtil.isLocationEnable(this)){
                showToast("请打开位置信息开关");
                BLEPermissionUtil.requestLocationService(this);
                return;
            }
        }
        //开始扫描
        try {
            clearAdapter();
            startScanBLE(onlyScanConfiguredBLE,new BleScanCallback());
            isScanning=true;
            setProgressbarVisible(true);
            invalidateOptionsMenu();
        }catch ( Exception e){
            showToast(e.getMessage());
        }
    }
    private void stopScan(){
        try {
            stopScanBLE();
            isScanning=false;
            setProgressbarVisible(false);
            invalidateOptionsMenu();
        } catch (Exception e) {
            LogTool.d(e.getMessage());
        }
    }
    private void setResult(String mac){
        stopScan();
        LogTool.d(String.format("select device:",mac));
        //check source and target
        if(sourceActivityClass!=null && targetActivityClass!=null
                && sourceActivityClass.equalsIgnoreCase(targetActivityClass)){
            //same activity
            Intent intent = new Intent();
            intent.putExtra(IntentConstant.SCAN_SELECT_DEVICE,mac);
            setResult(RESULT_OK,intent);    //返回到主页面
            finish();
        }else{
            if(targetActivityClass!=null){
                try {
                    Intent intent = new Intent(this, Class.forName(targetActivityClass));
                    intent.putExtra(IntentConstant.SCAN_SELECT_DEVICE, mac);
                    activityResult.launch(intent);//跳转到配置节点活动对象
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    private void clearAdapter(){
      this.runOnUiThread(() -> {
          adapter.clear();
      });
    }
    private void setProgressbarVisible(boolean visible){
        runOnUiThread(()->{
            pbIndicator.setVisibility(visible? View.VISIBLE:View.INVISIBLE);
        });
    }
   private class BleScanCallback extends ScanCallback{
       @RequiresApi(api = Build.VERSION_CODES.S)
       @SuppressLint("MissingPermission")
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
          int type=  result.getDevice().getType();
          if(type==BluetoothDevice.DEVICE_TYPE_LE){
              Map<String,String> mapDev= analysisData(result.getScanRecord().getBytes());
              BleDevice bleDevice=new BleDevice();
              if(mapDev!=null) {
                  if(mapDev.containsKey(KEY_ALIAS)) {
                      bleDevice.setAlias(mapDev.get(KEY_ALIAS));
                  }else{
                      bleDevice.setAlias(result.getDevice().getName());
                  }
                  if(mapDev.containsKey(KEY_IDENTIFIER)){
                      bleDevice.setId(mapDev.get(KEY_IDENTIFIER));
                  }else{
                      bleDevice.setId(result.getDevice().getAddress());
                  }
              }else{
                  bleDevice.setAlias(result.getDevice().getName());
                  bleDevice.setId(result.getDevice().getAddress());
              }
              bleDevice.setName(result.getDevice().getName());
              bleDevice.setType(result.getDevice().getType());
              bleDevice.setRssi(result.getRssi());
              bleDevice.setAddress(result.getDevice().getAddress());
              if(filterDevices!=null && filterDevices.size()>0){
                  if(!filterDevices.contains(bleDevice.getAddress())){
                      adapter.update(bleDevice);
                  }
              }else{
                  adapter.update(bleDevice);
              }
          }
        }
    }

    /**
     * 从数据中解析出蓝牙名称中的实际名称和mac地址
     * @param data 扫描接收到的广播数据
     * @return
     */
    private Map<String,String> analysisData(byte[] data){
        if(data!=null) {
            int offset = 0;
            int length;
            while (offset < data.length) {
                length = data[offset];  //数据长度
                if (data[offset + 1] == 0x09) {  //蓝牙名称属性
                    byte[] bleName = ConvertUtil.subByte(data,offset,length + 1);
                    int nameLen;
                    for(nameLen=0;nameLen<bleName.length;nameLen++){
                        if(bleName[nameLen]==0x00){  //找到结束符
                        byte nameByte[]=ConvertUtil.subByte(bleName,2,nameLen-2); //将名称数据复制到nameByte
                        byte macByte[]=ConvertUtil.subByte(bleName,nameLen+1,bleName.length-nameLen-1);
                            Map<String,String> map=new HashMap<>();
                            map.put(KEY_ALIAS,new String(nameByte));
                            map.put(KEY_IDENTIFIER,ConvertUtil.fromByteArray2HexString(macByte));
                            return map;
                        }
                    }
                } else {
                    offset += length+1;
                }
            }
        }
        return null;
    }
}